﻿/*
 * Tencent is pleased to support the open source community by making xLua available.
 * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
 * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
 * http://opensource.org/licenses/MIT
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using XLua;
using System;

namespace HotUI{
	public enum enLoadLuaState{
		Idle = 0,
		Loading = 1,
		HasLua = 2,
		NoLua = 3,
	}
	public class MyLuaBehaviour : MonoBehaviour {
		public TextAsset luaScript;
		public string luaScriptPath;
		public Injection[] injections;
		public enLoadLuaState loadLuaState = enLoadLuaState.Idle;

		internal static LuaEnv luaEnv = new LuaEnv(); //all lua behaviour shared one luaenv only!
		internal static float lastGCTime = 0;
		internal const float GCInterval = 1;//1 second 
		bool luaStartcalled;
		private Action luaStart;
		private Action luaUpdate;
		private Action luaOnDestroy;

		private LuaTable scriptEnv;
		protected bool loadLuaFinish{
			get{
				return loadLuaState > enLoadLuaState.Loading;
			}
		}

		public static MyLuaBehaviour RunLua(string luaname){
			var obj = new GameObject (luaname).AddComponent<MyLuaBehaviour> ();
			obj.luaScript = GameTool.ResourcesLua(luaname) as TextAsset;
			obj.InitLua (false);
			return obj;
		}

		void Awake()
		{
			if (luaScript == null && luaScriptPath!=null &&  luaScriptPath != "") {
				var obj = GameTool.ResourcesLua (luaScriptPath);
				if (obj == null) {
					Debug.Log (string.Format("Resources Lua :{0} is null",luaScriptPath));
				}
				luaScript = obj as TextAsset;
			}

			if (luaScript == null) {
				loadLuaState = enLoadLuaState.NoLua;
				LoadLuaAssets ();
			}else{
				InitLua ();
			}
		}

		protected virtual void LoadLuaAssets(){
			
		}
		protected void InitLua(bool needStart = false){
			loadLuaState = enLoadLuaState.HasLua;
			scriptEnv = luaEnv.NewTable();

			LuaTable meta = luaEnv.NewTable();
			meta.Set("__index", luaEnv.Global);
			scriptEnv.SetMetaTable(meta);
			meta.Dispose();

			scriptEnv.Set("self", this);
			if (injections != null) {
				foreach (var injection in injections) {
					scriptEnv.Set (injection.name, injection.value);
				}
			}
			luaEnv.DoString (luaScript.text, "MyLuaBehaviour", scriptEnv);

			Action luaAwake = scriptEnv.Get<Action> ("awake");
			scriptEnv.Get ("start", out luaStart);
			scriptEnv.Get ("update", out luaUpdate);
			scriptEnv.Get ("ondestroy", out luaOnDestroy);
			BindLuaFun ();
			if (luaAwake != null) {
				luaAwake ();
			}

			if(needStart){
				if(luaStart!=null && !luaStartcalled){
					luaStartcalled = true;
					luaStart();
				}
			}
			OnLuaInited();

		}
		protected virtual void OnLuaInited(){
		}
		public Action CallLua(string funname){
			if(scriptEnv == null || funname == "")
				return null;
			Action luaAwake = scriptEnv.Get<Action> (funname);
			if(luaAwake != null)
				luaAwake();
			return luaAwake;
		}

		public void LuaAction(string name,out Action action){
			scriptEnv.Get(name,out action);
		}
		/// <summary>
		/// scriptEnv.Get("start", out luaStart);
		/// </summary>
		protected virtual void BindLuaFun(){
			
		}
		// Use this for initialization
		void Start ()
		{
			if (luaStart != null && !luaStartcalled)
			{
				luaStartcalled = true;
				luaStart();
			}
		}

		// Update is called once per frame
		void Update ()
		{
			if (luaUpdate != null)
			{
				luaUpdate();
			}
			if (Time.time - MyLuaBehaviour.lastGCTime > GCInterval)
			{
				luaEnv.Tick();
				MyLuaBehaviour.lastGCTime = Time.time;
			}
		}

		void OnDestroy()
		{
			if (luaOnDestroy != null)
			{
				luaOnDestroy();
			}
			luaOnDestroy = null;
			luaUpdate = null;
			luaStart = null;
			scriptEnv.Dispose();
			injections = null;
		}
	}

}